package com.yb0os1.aop;

import com.yb0os1.annotation.AutoFill;
import com.yb0os1.constant.AutoFillConstant;
import com.yb0os1.context.BaseContext;
import com.yb0os1.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/***
 * 自定义切面，实现公共字段的自动填充
 */
@Component
@Aspect
@Slf4j
public class WebAOP {
    //加入时间、操作人等方面的信息的切入点
    // 两个表达式都加入了 目的就是减小扫描范围
    @Pointcut("execution(* com.yb0os1.mapper.*.*(..)) && @annotation(com.yb0os1.annotation.AutoFill)")
    public void autoFillPointCut(){}

    //前置通知，赋值
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint){
        log.info("公共字段自动填充...");
        // 获取到当前被拦截的方法上的数据库操作类型
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();//方法签名
        AutoFill autoFill = methodSignature.getMethod().getAnnotation(AutoFill.class);//获取注解对象
        OperationType value = autoFill.value();//获得注解的value字段的值

        // 获取传入的参数的值  约定需要填充的就是第一个参数
        // 传入的是地址 所以在这里操作obj 在指定的方法也会被影响
        Object[] args = joinPoint.getArgs();
        if (args==null || args.length==0)return;
        Object arg = args[0];

        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        // 判断是update操作还是insert操作
        if (value == OperationType.INSERT){
            //对四个字段赋值
            // 利用反射 Object对象是没有set的方法 所以我们利用反射获取
            try {
                Method setCreateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class);
                Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME,LocalDateTime.class);
                Method setCreateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER,Long.class);
                Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER,Long.class);
                setCreateTime.invoke(arg,now);
                setUpdateTime.invoke(arg,now);
                setCreateUser.invoke(arg,currentId);
                setUpdateUser.invoke(arg,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else if (value == OperationType.UPDATE){
            //对两个字段赋值
            try {
                Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER,Long.class);
                Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME,LocalDateTime.class);
                setUpdateTime.invoke(arg,now);
                setUpdateUser.invoke(arg,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
